package com.xwaf.platform.web.filter;

import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xwaf.platform.common.utils.DateHelper;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * <p>
 * 日志过滤器
 * <p>
 * 
 * @author 李聪 <br>
 * @email xwaf_love@yeah.net <br>
 * @since JDK 1.8<br>
 * @date 2019年12月30日 上午9:35:14 <br>
 * @see 无<br>
 *      Copyright (c) 2019, xwaf_love@yeah.net All Rights Reserved.<br>
 */
@Slf4j
@Aspect
@Component
public class LogFilter {

	private static final ObjectMapper mapper = new ObjectMapper();

	private long startTimeMillis;

	private long endTimeMillis;

	@Pointcut("execution(* com.xwaf.platform.web.controller.*.*(..))")
	public void controller() {
	}

	@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
	public void requestMapping() {
	}

	@Before("controller()")
	public void doBefore(JoinPoint joinPoint) {
		startTimeMillis = System.currentTimeMillis();
		org.springframework.web.context.request.RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();
		log.info("===================== request start =====================", new Object[0]);
		log.info("URL:[ {} ],Token=[ {} ]", new Object[] { request.getRequestURL(), request.getHeader("Token") });
		printMap("Request Params", request.getParameterMap());
		log.info("===================== request end =====================\n", new Object[0]);
	}

	@After("controller()")
	public void doAfter(JoinPoint joinPoint) {
		endTimeMillis = System.currentTimeMillis();
	}

	@AfterReturning(pointcut = "controller()", returning = "returnValue")
	public JoinPoint afterReturning(JoinPoint joinPoint, Object returnValue) {
		log.info("===================== return start =====================", new Object[0]);
		org.springframework.web.context.request.RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();
		log.info("计时结束：{}  耗时：{}  URI: {}  最大内存: {}m  已分配内存: {}m  已分配内存中的剩余空间: {}m  最大可用内存: {}m",
				new SimpleDateFormat("hh:mm:ss.SSS").format(endTimeMillis),
				DateHelper.formatDateTime(endTimeMillis - startTimeMillis), request.getRequestURI(),
				Runtime.getRuntime().maxMemory() / 1024 / 1024, Runtime.getRuntime().totalMemory() / 1024 / 1024,
				Runtime.getRuntime().freeMemory() / 1024 / 1024, (Runtime.getRuntime().maxMemory()
						- Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024);
		log.info("===================== return end =====================\n", new Object[0]);
		return joinPoint;
	}

	@AfterThrowing(pointcut = "controller()", throwing = "e")
	public void afterThrowing(Throwable e) {
		log.error("ERROR:", new Object[] { e });
	}

	private void printMap(String prefix, Map map) {
		StringBuilder buf = new StringBuilder();
		for (Object o : map.entrySet()) {
			Map.Entry entry = (Map.Entry) o;
			buf.append("  ");
			buf.append((String) entry.getKey());
			buf.append(" = ");
			try {
				buf.append(mapper.writeValueAsString(entry.getValue()));
				buf.append("\n");
			} catch (IOException e) {
				log.error("print map error", new Object[] { e.getMessage() });
			}
		}
		if (buf.length() > 0)
			log.info("{}:\n{}", new Object[] { prefix, buf.substring(0, buf.length() - 1) });
	}

	/**
	 * 
	 * <p>
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * <p>
	 * 
	 * @author 李聪 <br>
	 * @email xwaf_love@yeah.net <br>
	 * @since JDK 1.8<br>
	 * @date 2019年12月30日 上午9:35:22 <br>
	 * @see 无<br>
	 * @param joinPoint
	 *            切点
	 * @return 方法描述
	 * @throws Exception
	 * @demo <br>
	 */
	public static Map<String, Object> getMethodInfo(JoinPoint joinPoint) throws Exception {
		Map<String, Object> map = new HashMap<String, Object>(16);
		// 获取目标类名
		String targetName = joinPoint.getTarget().getClass().getName();
		// 获取方法名
		String methodName = joinPoint.getSignature().getName();
		// 获取相关参数
		Object[] arguments = joinPoint.getArgs();
		// 生成类对象
		Class targetClass = Class.forName(targetName);
		// 获取该类中的方法
		Method[] methods = targetClass.getMethods();
		return map;
	}
}
